package com.tpc.jginterface.util.http;

import com.alibaba.fastjson2.JSON;
import okhttp3.Callback;
import okhttp3.ConnectionPool;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * ok http client
 *
 * @author duwenlei
 * @date 2024年8月5日
 */
public class OkHttpClients {
    // http client
    private static volatile OkHttpClient okHttpClient = null;
    // 请求头
    private Map<String, String> headers;
    // 请求数据
    private Map<String, Object> params;
    private String reqData;
    // 请求地址
    private String uri;
    // 实际请求
    private Request.Builder requestBuilder;

    private OkHttpClients() {
        if (okHttpClient == null) {
            ConnectionPool connectionPool = new ConnectionPool(500, 5, TimeUnit.SECONDS);
            okHttpClient = new OkHttpClient.Builder()
                    .connectionPool(connectionPool)
                    .connectTimeout(20, TimeUnit.SECONDS)
                    .readTimeout(20, TimeUnit.SECONDS)
                    .writeTimeout(20, TimeUnit.SECONDS)
                    .build();
        }
        this.headers = new HashMap<>();
    }

    public static OkHttpClients builder() {
        return new OkHttpClients();
    }

    /**
     * 设置资源地址
     *
     * @param uri 资源地址
     * @return
     */
    public OkHttpClients setUri(String uri) {
        this.uri = uri;
        return this;
    }

    /**
     * 设置请求参数
     *
     * @param paramKey   键值
     * @param paramValue 实际值
     * @return
     */
    public OkHttpClients addParam(String paramKey, Object paramValue) {
        if (params == null) {
            params = new HashMap<>();
        }
        params.put(paramKey, paramValue);
        return this;
    }

    /**
     * 批量设置请求参数
     *
     * @param params
     * @return
     */
    public OkHttpClients addParams(Map<String, Object> params) {
        this.params = params;
        return this;
    }

    public OkHttpClients addReqData(String reqData) {
        this.reqData = reqData;
        return this;
    }

    /**
     * 设置请求头
     *
     * @param headerKey   headerKey
     * @param headerValue headerValue
     * @return
     */
    public OkHttpClients addHeader(String headerKey, String headerValue) {
        if (headers == null) {
            headers = new HashMap<>();
        }
        headers.put(headerKey, headerValue);
        return this;
    }

    /**
     * method : get
     *
     * @return
     */
    public OkHttpClients get() throws UnsupportedEncodingException {
        requestBuilder = new Request.Builder().get();
        StringBuilder sb = new StringBuilder(this.uri);
        if (params != null) {
            sb.append("?");
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                sb.append(URLEncoder.encode(entry.getKey(), "utf-8"));
                sb.append("=");
                sb.append(URLEncoder.encode((String) entry.getValue(), "utf-8"));
                sb.append("&");
            }
        }
        requestBuilder.url(sb.toString());
        return this;
    }

    /**
     * method : post
     *
     * @return
     */
    public OkHttpClients post(BodyType bodyType) {
        RequestBody requestBody;
        switch (bodyType) {
            case FORM_BODY:
                FormBody.Builder formBody = new FormBody.Builder();
                if (params != null) {
                    params.forEach((k, v) -> formBody.add(k, (String) v));
                }
                requestBody = formBody.build();
                break;
            case JSON_BODY:
                // 如果直接提供了reqData，使用它作为JSON请求体
                String jsonStr;
                if (reqData != null) {
                    jsonStr = reqData;
                } else if (params != null) {
                    jsonStr = JSON.toJSONString(params);
                } else {
                    jsonStr = "{}";
                }
                requestBody = RequestBody.create(
                        MediaType.parse("application/json; charset=utf-8"),
                        jsonStr);
                break;
            case MULTIPART_BODY:
                MultipartBody.Builder builder = new MultipartBody.Builder();
                for (Map.Entry<String, Object> stringObjectEntry : params.entrySet()) {
                    String key = stringObjectEntry.getKey();
                    Object value = stringObjectEntry.getValue();
                    if (value instanceof String) {
                        builder.addFormDataPart(key, value.toString());
                    } else {
                        builder.addFormDataPart(key, key,
                                RequestBody.create((byte[]) value, MediaType.parse("application/from-data")));
                    }
                }
                requestBody = builder.build();
                break;
            case STRING:
                requestBody = RequestBody.create(
                        MediaType.parse("application/json; charset=utf-8"),
                        reqData != null ? reqData : "");
                break;
            default:
                throw new EnumConstantNotPresentException(BodyType.class, bodyType.name());
        }
        requestBuilder = new Request.Builder()
                .post(requestBody)
                .url(this.uri);
        return this;
    }

    private void setHeaderMap(Request.Builder requestBuilder) {
        if (headers != null) {
            headers.forEach(requestBuilder::addHeader);
        }
    }

    /**
     * 同步执行请求
     *
     * @return
     */
    public String sync() throws IOException {
        setHeaderMap(requestBuilder);
        final Response response = okHttpClient.newCall(requestBuilder.build()).execute();
        return Objects.requireNonNull(response.body()).string();
    }

    /**
     * 同步执行请求
     *
     * @return
     */
    public Object sync(BodyType bodyType) throws IOException {
        setHeaderMap(requestBuilder);
        final Response response = okHttpClient.newCall(requestBuilder.build()).execute();
        switch (bodyType) {
            case STRING:
                return Objects.requireNonNull(response.body()).string();
            case BYTE:
                return Objects.requireNonNull(response.body()).bytes();
            default:
                return Objects.requireNonNull(response.body()).string();
        }
    }

    /**
     * 异步执行请求
     *
     * @return
     */
    public void async(Callback callback) throws IOException {
        setHeaderMap(requestBuilder);
        okHttpClient.newCall(requestBuilder.build()).enqueue(callback);
    }

}